//
//  YSSqliteModelTool.m
//  YSSqliteTool_Example
//
//  Created by Kyson on 2018/12/4.
//  Copyright © 2018 kysonyangs. All rights reserved.
//

#import "YSSqliteModelTool.h"
#import "YSModelTool.h"
#import "YSSqliteTool.h"
#import "YSTableTool.h"

@implementation YSSqliteModelTool

+ (BOOL)createTable:(Class)cls uid:(NSString *)uid {
    // 创建表格sql拼接
    // 1.1 获取表格名称
    NSString *tableName = [YSModelTool tableName:cls];
    
    if (![cls respondsToSelector:@selector(primaryKey)]) {
        NSLog(@"如果要操作模型，必须实现 + (NSString *)primaryKey; 方法说明主键信息");
        return NO;
    }
    
    NSString *primaryKey = [cls primaryKey];
    
    // 1.2 获取模型所有字段与类型
    NSString *createTbaleSql = [NSString stringWithFormat:@"create table if not exists %@(%@, primary key(%@))", tableName, [YSModelTool columnNamesAndTypesStr:cls], primaryKey];
    
    // 2. 执行
    return [YSSqliteTool deal:createTbaleSql uid:uid];
}

+ (BOOL)isTableRequiredUpdate:(Class)cls uid:(NSString *)uid {
    NSArray *modelName = [YSModelTool allTableSortedIvarName:cls];
    NSArray *tableName = [YSTableTool tableSortedColumnNames:cls uid:uid];
    
    if (modelName.count != tableName.count) {
        return NO;
    }
    
    for (int i = 0; i < modelName.count; i++) {
        if (![[modelName[i] lowercaseString] isEqualToString:[tableName[i] lowercaseString]]) {
            return NO;
        }
    }
    return YES;
}

+ (BOOL)updateTable:(Class)cls uid:(NSString *)uid {
    // 1. 创建临时表
    // 创建表格sql拼接
    // 1.1 获取表格名称
    NSString *tableName = [YSModelTool tableName:cls];
    NSString *tmpTableName = [YSModelTool tmpTableName:cls];
    
    if (![cls respondsToSelector:@selector(primaryKey)]) {
        NSLog(@"如果要操作模型，必须实现 + (NSString *)primaryKey; 方法说明主键信息");
        return NO;
    }
    
    NSString *primaryKey = [cls primaryKey];
    
    NSMutableArray *execSqls = [NSMutableArray array];
    
    /// 防止没回滚成功造成数据库已存在的问题
    NSString *deleteTmpTable = [NSString stringWithFormat:@"drop table if exists %@", tmpTableName];
    [execSqls addObject:deleteTmpTable];
    
    // 1.2 获取模型所有字段与类型
    NSString *createTbaleSql = [NSString stringWithFormat:@"create table if not exists %@(%@, primary key(%@))", tmpTableName, [YSModelTool columnNamesAndTypesStr:cls], primaryKey];
    [execSqls addObject:createTbaleSql];
    // 2. 根据主键插入数据
    NSString *insertPrimaryKeyData = [NSString stringWithFormat:@"insert into %@(%@) select %@ from %@;", tmpTableName, primaryKey, primaryKey, tableName];
    [execSqls addObject:insertPrimaryKeyData];
    
    // 3. 根据主键更新数据
    NSArray *oldNames = [YSTableTool tableSortedColumnNames:cls uid:uid];
    NSArray *newNames = [YSModelTool allTableSortedIvarName:cls];
    
    NSDictionary *newNameToOldNameDic = nil;
    if ([cls respondsToSelector:@selector(newNameToOldNameDic)]) {
        newNameToOldNameDic = [cls newNameToOldNameDic];
    }
    
    for (NSString *columnName in newNames) {
        
        NSString *newColumnName = [newNameToOldNameDic objectForKey:columnName] ?: columnName;
        
        if (![oldNames containsObject:newColumnName]) {
            continue;
        }
        NSString *updateSql = [NSString stringWithFormat:@"update %@ set %@ = (select %@ from %@ where %@.%@ = %@.%@);", tmpTableName, columnName, newColumnName, tableName, tmpTableName, primaryKey, tableName, primaryKey];
        [execSqls addObject:updateSql];
    }
    
    NSString *deleteOldTable = [NSString stringWithFormat:@"drop table if exists %@", tableName];
    [execSqls addObject:deleteOldTable];
    
    NSString *renameTableName = [NSString stringWithFormat:@"alter table %@ rename to %@", tmpTableName, tableName];
    [execSqls addObject:renameTableName];
        
    return [YSSqliteTool dealSqls:execSqls uid:uid];
}
    
+ (BOOL)saveOrUpdateModel:(id)model uid:(NSString *)uid {
    
    Class cls = [model class];
    // 1. 表是否存在 不存在创建
    if (![YSTableTool isTableExists:cls uid:uid]) {
        if (![self createTable:cls uid:uid]) {
            return NO;
        }
    }
    
    // 2. 表是否需要更新，需要 则 更新
    if (![self isTableRequiredUpdate:cls uid:uid]) {
        if (![self updateTable:cls uid:uid]) {
            return NO;
        }
    }
    
    NSString *tableName = [YSModelTool tableName:cls];
    if (![cls respondsToSelector:@selector(primaryKey)]) {
        NSLog(@"如果要操作模型，必须实现 + (NSString *)primaryKey; 方法说明主键信息");
        return NO;
    }
    NSString *primaryKey = [cls primaryKey];
    
    id primaryValue = [model valueForKeyPath:primaryKey];
    
    // 3. 记录是否存在
    // 3.1 存在 更新
    NSString *checkSql = [NSString stringWithFormat:@"select * from %@ where %@ = '%@'", tableName, primaryKey, primaryValue];
    NSArray *result = [YSSqliteTool querySql:checkSql uid:uid];
    
    // 获取字段数组
    NSArray *columnNames = [YSModelTool classIvarNameTypeDic:cls].allKeys;

    // 获取值数组
    // model keypaths
    NSMutableArray *columnValues = [NSMutableArray array];
    for (NSString *column in columnNames) {
        id value = [model valueForKeyPath:column];
        
        if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
            // 在这里, 把字典或者数组, 处理成为一个字符串, 保存到数据库里面去
            // 字典/数组 -> data
            NSData *data = [NSJSONSerialization dataWithJSONObject:value options:NSJSONWritingPrettyPrinted error:nil];
            
            // data -> nsstring
            value = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        }
        
        [columnValues addObject:value ?: @""];
    }
    
    NSString *execSql = @"";
    if (result.count > 0) {
        NSMutableArray *columnValueStrs = [NSMutableArray array];
        for (int i = 0; i < columnNames.count; i++) {
            NSString *name = columnNames[i];
            if (![name isEqualToString:primaryKey]) {
                NSString *value = columnValues[i];
                [columnValueStrs addObject:[NSString stringWithFormat:@"%@='%@'", name, value]];
            }
        }
        NSString *columnValueString = [columnValueStrs componentsJoinedByString:@","];
        
        // 更新
        execSql = [NSString stringWithFormat:@"update %@ set %@ where %@ = '%@'", tableName, columnValueString, primaryKey, primaryValue];
    } else {
        NSString *columnNameString = [columnNames componentsJoinedByString:@","];
        
        NSMutableArray *valueStrs = [NSMutableArray array];
        for (NSString *value in columnValues) {
            [valueStrs addObject:[NSString stringWithFormat:@"'%@'", value]];
        }
        
        NSString *columnValueString = [valueStrs componentsJoinedByString:@","];

        execSql = [NSString stringWithFormat:@"insert into %@(%@) values(%@)", tableName, columnNameString, columnValueString];
    }
    
    return [YSSqliteTool deal:execSql uid:uid];    
}

+ (BOOL)deleteModel:(id)model uid:(NSString *)uid {
    Class cls = [model class];
    NSString *tableName = [YSModelTool tableName:cls];
    if (![cls respondsToSelector:@selector(primaryKey)]) {
        NSLog(@"如果要操作模型，必须实现 + (NSString *)primaryKey; 方法说明主键信息");
        return NO;
    }
    NSString *primaryKey = [cls primaryKey];
    
    id primaryValue = [model valueForKeyPath:primaryKey];
    
    NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@ = '%@'", tableName, primaryKey, primaryValue];
    
    return [YSSqliteTool deal:deleteSql uid:uid];
}

+ (BOOL)deleteModel:(Class)cls whereStr:(NSString *)whereStr uid:(NSString *)uid {
    if (whereStr.length == 0) {
        NSLog(@"请添加条件在进行删除 ");
        return NO;
    }
    
    NSString *tableName = [YSModelTool tableName:cls];
    
    NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@", tableName, whereStr];
    
    return [YSSqliteTool deal:deleteSql uid:uid];
}

+ (BOOL)deleteModel:(Class)cls columnName:(NSString *)name relationType:(RelationType)type value:(id)value uid:(NSString *)uid {
    if (name.length == 0 || !value) {
        NSLog(@"请添加条件在进行删除 ");
        return NO;
    }
    
    NSString *tableName = [YSModelTool tableName:cls];
    
    NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@ %@ '%@'", tableName, name, self.RelationTypeDic[@(type)], value];
    
    return [YSSqliteTool deal:deleteSql uid:uid];
}

+ (NSArray *)queryAllModels:(Class)cls uid:(NSString *)uid {
    NSString *tableName = [YSModelTool tableName:cls];
    // 1. sql
    NSString *sql = [NSString stringWithFormat:@"select * from %@", tableName];
    
    // 2. 执行查询,
    // key value
    // 模型的属性名称, 和属性值
    // xx 字符串
    // oo 字符串
    NSArray <NSDictionary *>*results = [YSSqliteTool querySql:sql uid:uid];
    
    // 3. 处理查询的结果集 -> 模型数组
    return [self parseResults:results withClass:cls];;
}

+ (NSArray *)queryModels:(Class)cls columnName:(NSString *)name relationType:(RelationType)type value:(id)value uid:(NSString *)uid {
    NSString *tableName = [YSModelTool tableName:cls];
    // 1. 拼接sql语句
    NSString *sql = [NSString stringWithFormat:@"select * from %@ where %@ %@ '%@' ", tableName, name, self.RelationTypeDic[@(type)], value];
    
    // 2. 查询结果集
    NSArray <NSDictionary *>*results = [YSSqliteTool querySql:sql uid:uid];
    
    return [self parseResults:results withClass:cls];
}

+ (NSArray *)queryModels:(Class)cls WithSql:(NSString *)sql uid:(NSString *)uid {
    // 2. 查询结果集
    NSArray <NSDictionary *>*results = [YSSqliteTool querySql:sql uid:uid];
    
    return [self parseResults:results withClass:cls];
    
}

+ (NSArray *)parseResults:(NSArray <NSDictionary *>*)results withClass:(Class)cls {
    // 3. 处理查询的结果集 -> 模型数组
    NSMutableArray *models = [NSMutableArray array];
    
    // 属性名称 -> 类型 dic
    NSDictionary *nameTypeDic = [YSModelTool classIvarNameTypeDic:cls];
    
    for (NSDictionary *modelDic in results) {
        id model = [[cls alloc] init];
        [models addObject:model];
        
        [modelDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            
            // xx NSMutableArray
            // oo NSDictionary
            //            [
            //            "2",
            //            "3"
            //            ]
            NSString *type = nameTypeDic[key];
            //            NSArray
            //            NSMutableArray
            //            NSDictionary
            //            NSMutableDictionary
            id resultValue = obj;
            if ([type isEqualToString:@"NSArray"] || [type isEqualToString:@"NSDictionary"]) {
                
                // 字符串 ->
                NSData *data = [obj dataUsingEncoding:NSUTF8StringEncoding];
                resultValue = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
                
            } else if ([type isEqualToString:@"NSMutableArray"] || [type isEqualToString:@"NSMutableDictionary"]) {
                NSData *data = [obj dataUsingEncoding:NSUTF8StringEncoding];
                resultValue = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
            }
            
            [model setValue:resultValue forKeyPath:key];            
        }];
    }
    
    return models;
}

+ (NSDictionary *)RelationTypeDic {
    return @{
             @(RelationTypeMore):@">",
             @(RelationTypeLess):@"<",
             @(RelationTypeEqual):@"=",
             @(RelationTypeMoreEqual):@">=",
             @(RelationTypeLessEqual):@"<="
             };
}

@end
